/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 * Description: log_level.cpp
 */

#include "infra/log/log_level.h"

#include <string>
#include <mutex>
#include <atomic>
#include <algorithm>

namespace {
const size_t MAX_MODULE_SIZE = 64;
}

namespace hiai {

class LogLevel {
public:
    static LogLevel& Instance()
    {
        static LogLevel instance;
        return instance;
    }

    bool SetLogLevel(const char* moduleName, AI_LogPriority priority)
    {
        if (moduleName == nullptr) {
            AI_LOGE("AI_LOG", "Module name is null, set log level fail.");
            return false;
        }
        if (priority < AI_LogPriority::AI_LOG_DEBUG || priority > AI_LogPriority::AI_LOG_ERROR) {
            AI_LOGE("AI_LOG", "Log level is illegal, set log level fail.");
            return false;
        }

        std::lock_guard<std::mutex> lk(updateMutex_);
        auto customLogLevelSize = customLogLevelSize_.load();
        auto iter = std::find_if(logLevels_, logLevels_ + customLogLevelSize,
            [moduleName](LogLevelItem& item) { return item.module == moduleName; });
        if (iter != &logLevels_[customLogLevelSize]) {
            iter->priority = priority;
            return true;
        } else {
            if (customLogLevelSize == MAX_MODULE_SIZE) {
                AI_LOGE("AI_LOG", "the modules specified custom log level is too much.");
                return false;
            }

            auto& curr = logLevels_[customLogLevelSize];
            curr.module = moduleName;
            curr.priority = priority;

            customLogLevelSize_++;
        }
        return true;
    }

    AI_LogPriority GetLogLevel(const char* moduleName)
    {
        if (moduleName == nullptr) {
            AI_LOGW("AI_LOG", "Module name is null, Please check.");
            return AI_LogPriority::AI_LOG_DEBUG; // 默认日志级别为DEBUG，由系统的级别控制最终日志是否打印。
        }

        size_t customLogLevelSize = customLogLevelSize_.load();
        auto iter = std::find_if(logLevels_, logLevels_ + customLogLevelSize,
            [moduleName](LogLevelItem& item) { return item.module == moduleName; });
        return iter == &logLevels_[customLogLevelSize] ? AI_LogPriority::AI_LOG_DEBUG : iter->priority;
    }

private:
    struct LogLevelItem {
        std::string module;
        AI_LogPriority priority;
    };

    std::mutex updateMutex_;
    LogLevelItem logLevels_[MAX_MODULE_SIZE + 1];
    std::atomic<size_t> customLogLevelSize_ {0};
};
} // namespace hiai

bool AI_Log_SetLevel(const char* moduleName, AI_LogPriority priority)
{
    return hiai::LogLevel::Instance().SetLogLevel(moduleName, priority);
}

AI_LogPriority AI_Log_GetLevel(const char* moduleName)
{
    return hiai::LogLevel::Instance().GetLogLevel(moduleName);
}
